home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #1 / Ham Radio 2000.iso / ham2000 / tcp_ip / wnos / wn941101 / conversd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-10  |  30.5 KB  |  1,123 lines

  1. static char  rcsid[] = "@(#) $Header: conversd.c,v 2.17 91/06/17 14:13:37 deyke Exp $";
  2.  
  3. #define _HPUX_SOURCE
  4. #include <sys/types.h>
  5. #include <ctype.h>
  6. #include <fcntl.h>
  7. #include <signal.h>
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <time.h>
  12. /*
  13. #include <sys/socket.h>
  14. #include <sys/stat.h>
  15. #include <sys/utsname.h>
  16. #include <unistd.h>
  17. #include <utmp.h>
  18. */
  19. #include "global.h"
  20. #include "config.h"
  21. #include "ax25.h"
  22.  
  23. #define MAXCHANNEL 32767
  24.  
  25. struct connection {
  26.   int  type;                    /* Connection type */
  27. #define CT_UNKNOWN      0
  28. #define CT_USER         1
  29. #define CT_HOST         2
  30. #define CT_CLOSED       3
  31.   char  name[80];               /* Name of user or host */
  32.   char  host[80];                 /* Name of host where user is logged on *
  33.   struct connection *via;       /* Pointer to neighbor host */
  34.   int  channel;                 /* Channel number */
  35.   long  time;                   /* Connect time */
  36.   int  locked;                  /* Set if mesg already sent */
  37.   int  fd;                        /* Socket descriptor */
  38.   int  fmask;                   /* Socket mask */
  39.   char  ibuf[2048];             /* Input buffer */
  40.   int  icnt;                    /* Number of bytes in input buffer */
  41.   struct mbuf *obuf;            /* Output queue */
  42.   int  received;                /* Number of bytes received */
  43.   int  xmitted;                 /* Number of bytes transmitted */
  44.   struct connection *next;      /* Linked list pointer */
  45. };
  46.  
  47. #define CM_UNKNOWN   (1 << CT_UNKNOWN)
  48. #define CM_USER      (1 << CT_USER)
  49. #define CM_HOST      (1 << CT_HOST)
  50. #define CM_CLOSED    (1 << CT_CLOSED)
  51.  
  52. #define NULLCONNECTION  ((struct connection *) 0)
  53.  
  54. struct permlink {
  55.   char  name[80];               /* Name of host */
  56.   char  socket[80];             /* Name of socket to connect to */
  57.   char  command[256];           /* Optional connect command */
  58.   struct connection *connection;/* Pointer to associated connection */
  59.   long  statetime;              /* Time of last (dis)connect */
  60.   int  tries;                   /* Number of connect tries */
  61.   long  waittime;               /* Time between connect tries */
  62.   long  retrytime;              /* Time of next connect try */
  63.   struct permlink *next;        /* Linked list pointer */
  64. };
  65.  
  66. #define NULLPERMLINK  ((struct permlink *) 0)
  67.  
  68. static char  *myhostname;
  69. static long  currtime;
  70. static struct connection *connections;
  71. static struct permlink *permlinks;
  72.  
  73. static void sigpipe_handler __ARGS((int sig, int code, struct sigcontext *scp));
  74. static void appendstring __ARGS((struct mbuf **bpp, char *string));
  75. static int queuelength __ARGS((struct mbuf *bp));
  76. static void free_connection __ARGS((struct connection *cp));
  77. static void free_closed_connections __ARGS((void));
  78. static char *getarg __ARGS((char *line, int all));
  79. static char *formatline __ARGS((char *prefix, char *text));
  80. static char *timestring __ARGS((long gmt));
  81. static struct connection *alloc_connection __ARGS((int fd));
  82. static void accept_connect_request __ARGS((int flisten));
  83. static void clear_locks __ARGS((void));
  84. static void send_user_change_msg __ARGS((char *name, char *host, int oldchannel, int newchannel));
  85. static void send_msg_to_user __ARGS((char *fromname, char *toname, char *text));
  86. static void send_msg_to_channel __ARGS((char *fromname, int channel, char *text));
  87. static void send_invite_msg __ARGS((char *fromname, char *toname, int channel));
  88. static void update_permlinks __ARGS((char *name, struct connection *cp));
  89. static void connect_permlinks __ARGS((void));
  90. static void bye_command __ARGS((struct connection *cp));
  91. static void channel_command __ARGS((struct connection *cp));
  92. static void help_command __ARGS((struct connection *cp));
  93. static void invite_command __ARGS((struct connection *cp));
  94. static void links_command __ARGS((struct connection *cp));
  95. static void msg_command __ARGS((struct connection *cp));
  96. static void name_command __ARGS((struct connection *cp));
  97. static void who_command __ARGS((struct connection *cp));
  98. static void h_cmsg_command __ARGS((struct connection *cp));
  99. static void h_host_command __ARGS((struct connection *cp));
  100. static void h_invi_command __ARGS((struct connection *cp));
  101. static void h_umsg_command __ARGS((struct connection *cp));
  102. static void h_user_command __ARGS((struct connection *cp));
  103. static void process_input __ARGS((struct connection *cp));
  104. static void read_configuration __ARGS((void));
  105.  
  106.  
  107. /*---------------------------------------------------------------------------*/
  108.  
  109. static void appendstring(bpp, string)
  110. struct mbuf **bpp;
  111. char  *string;
  112. {
  113.   register struct mbuf *bp, *p;
  114.  
  115.   if (!*string) return;
  116.  
  117.   bp = (struct mbuf *) mxallocw(sizeof(struct mbuf ) + strlen(string) + 1);
  118.   bp->next = NULLBUF;
  119.   bp->data = strcpy((char *) (bp + 1), string);
  120.  
  121.   if (*bpp) {
  122.     for (p = *bpp; p->next; p = p->next) ;
  123.     p->next = bp;
  124.   } else
  125.     *bpp = bp;
  126. }
  127.  
  128. /*---------------------------------------------------------------------------*/
  129.  
  130. static int  queuelength(bp)
  131. register struct mbuf *bp;
  132. {
  133.   register int  len;
  134.  
  135.   for (len = 0; bp; bp = bp->next)
  136.     len += strlen(bp->data);
  137.   return len;
  138. }
  139.  
  140. /*---------------------------------------------------------------------------*/
  141.  
  142. static void free_connection(cp)
  143. register struct connection *cp;
  144. {
  145.   register struct permlink *p;
  146.  
  147.   for (p = permlinks; p; p = p->next)
  148.     if (p->connection == cp) p->connection = NULLCONNECTION;
  149.   if (cp->fmask) close(cp->fd);
  150.   free_q(&cp->obuf);
  151.   xfree((char *) cp);
  152. }
  153.  
  154. /*---------------------------------------------------------------------------*/
  155.  
  156. static void free_closed_connections()
  157. {
  158.   register struct connection *cp, *p;
  159.  
  160.   for (p = NULLCONNECTION, cp = connections; cp; )
  161.     if (cp->type == CT_CLOSED ||
  162.     cp->type == CT_UNKNOWN && cp->time + 300 < currtime) {
  163.       if (p) {
  164.     p->next = cp->next;
  165.     free_connection(cp);
  166.     cp = p->next;
  167.       } else {
  168.     connections = cp->next;
  169.     free_connection(cp);
  170.     cp = connections;
  171.       }
  172.     } else {
  173.       p = cp;
  174.       cp = cp->next;
  175.     }
  176. }
  177.  
  178. /*---------------------------------------------------------------------------*/
  179.  
  180. static char  *getarg(line, all)
  181. char  *line;
  182. int  all;
  183. {
  184.  
  185.   char  *arg;
  186.   int  c;
  187.   static char  *p;
  188.  
  189.   if (line) p = line;
  190.   while (isspace(uchar(*p))) p++;
  191.   if (all) return p;
  192.   arg = p;
  193.   while (*p && !isspace(uchar(*p))) {
  194.     c = tolower(uchar(*p));
  195.     *p++ = c;
  196.   }
  197.   if (*p) *p++ = '\0';
  198.   return arg;
  199. }
  200.  
  201. /*---------------------------------------------------------------------------*/
  202.  
  203. static char  *formatline(prefix, text)
  204. char  *prefix, *text;
  205. {
  206.  
  207. #define PREFIXLEN 10
  208. #define LINELEN   79
  209.  
  210.   register char  *f, *t, *x;
  211.   register int  l, lw;
  212.  
  213.   static char  buf[2048];
  214.  
  215.   for (f = prefix, t = buf; *f; *t++ = *f++) ;
  216.   l = t - buf;
  217.   f = text;
  218.  
  219.   for (; ; ) {
  220.     while (isspace(uchar(*f))) f++;
  221.     if (!*f) {
  222.       *t++ = '\n';
  223.       *t = '\0';
  224.       return buf;
  225.     }
  226.     for (x = f; *x && !isspace(uchar(*x)); x++) ;
  227.     lw = x - f;
  228.     if (l > PREFIXLEN && l + 1 + lw > LINELEN) {
  229.       *t++ = '\n';
  230.       l = 0;
  231.     }
  232.     do {
  233.       *t++ = ' ';
  234.       l++;
  235.     } while (l < PREFIXLEN);
  236.     while (lw--) {
  237.       *t++ = *f++;
  238.       l++;
  239.     }
  240.   }
  241. }
  242.  
  243. /*---------------------------------------------------------------------------*/
  244.  
  245. static char  *timestring(gmt)
  246. long  gmt;
  247. {
  248.  
  249.   static char  buffer[80];
  250.   static char  monthnames[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
  251.   struct tm *tm;
  252.  
  253.   tm = localtime(&gmt);
  254.   if (gmt + 24 * 60 * 60 > currtime)
  255.     sprintf(buffer, " %2d:%02d", tm->tm_hour, tm->tm_min);
  256.   else
  257.     sprintf(buffer, "%-3.3s %2d", monthnames + 3 * tm->tm_mon, tm->tm_mday);
  258.   return buffer;
  259. }
  260.  
  261. /*---------------------------------------------------------------------------*/
  262.  
  263. static struct connection *alloc_connection(fd)
  264. int  fd;
  265. {
  266.  
  267.   int  flags;
  268.   struct connection *cp;
  269.  
  270.   if ((flags = fcntl(fd, F_GETFL, 0)) == -1) {
  271.     close(fd);
  272.     return 0;
  273.   }
  274.   if (fcntl(fd, F_SETFL, flags | O_NDELAY) == -1) {
  275.     close(fd);
  276.     return 0;
  277.   }
  278.   cp = (struct connection *) cxallocw(1, sizeof(struct connection ));
  279.   cp->fd = fd;
  280.   cp->fmask = (1 << fd);
  281.   cp->time = currtime;
  282.   cp->next = connections;
  283.   return connections = cp;
  284. }
  285.  
  286. /*---------------------------------------------------------------------------*/
  287.  
  288. static void accept_connect_request(flisten)
  289. int  flisten;
  290. {
  291.  
  292.   int  addrlen;
  293.   int  fd;
  294.   struct sockaddr addr;
  295.  
  296.   addrlen = sizeof(addr);
  297.   if ((fd = accept(flisten, &addr, &addrlen)) >= 0) alloc_connection(fd);
  298. }
  299.  
  300. /*---------------------------------------------------------------------------*/
  301.  
  302. static void clear_locks()
  303. {
  304.   register struct connection *p;
  305.  
  306.   for (p = connections; p; p = p->next) p->locked = 0;
  307. }
  308.  
  309. /*---------------------------------------------------------------------------*/
  310.  
  311. static void send_user_change_msg(name, host, oldchannel, newchannel)
  312. char  *name, *host;
  313. int  oldchannel, newchannel;
  314. {
  315.  
  316.   char  buffer[2048];
  317.   register struct connection *p;
  318.  
  319.   for (p = connections; p; p = p->next) {
  320.     if (p->type == CT_USER && !p->via && !p->locked) {
  321.       if (p->channel == oldchannel) {
  322.     if (newchannel >= 0)
  323.       sprintf(buffer, "*** %s switched to channel %d.\n", name, newchannel);
  324.     else
  325.       sprintf(buffer, "*** %s signed off.\n", name);
  326.     appendstring(&p->obuf, buffer);
  327.     p->locked = 1;
  328.       }
  329.       if (p->channel == newchannel) {
  330.     sprintf(buffer, "*** %s signed on.\n", name);
  331.     appendstring(&p->obuf, buffer);
  332.     p->locked = 1;
  333.       }
  334.     }
  335.     if (p->type == CT_HOST && !p->locked) {
  336.       sprintf(buffer, "/\377\200USER %s %s %d %d %d\n", name, host, 0, oldchannel, newchannel);
  337.       appendstring(&p->obuf, buffer);
  338.       p->locked = 1;
  339.     }
  340.   }
  341. }
  342.  
  343. /*---------------------------------------------------------------------------*/
  344.  
  345. static void send_msg_to_user(fromname, toname, text)
  346. char  *fromname, *toname, *text;
  347. {
  348.  
  349.   char  buffer[2048];
  350.   register struct connection *p;
  351.  
  352.   for (p = connections; p; p = p->next)
  353.     if (p->type == CT_USER && !strcmp(p->name, toname))
  354.       if (p->via) {
  355.     if (!p->via->locked) {
  356.       sprintf(buffer, "/\377\200UMSG %s %s %s\n", fromname, toname, text);
  357.       appendstring(&p->via->obuf, buffer);
  358.       p->via->locked = 1;
  359.     }
  360.       } else {
  361.     if (!p->locked) {
  362.       if (strcmp(fromname, "conversd")) {
  363.         sprintf(buffer, "<*%s*>:", fromname);
  364.         appendstring(&p->obuf, formatline(buffer, text));
  365.       } else {
  366.         appendstring(&p->obuf, text);
  367.         appendstring(&p->obuf, "\n");
  368.       }
  369.       p->locked = 1;
  370.     }
  371.       }
  372. }
  373.  
  374. /*---------------------------------------------------------------------------*/
  375.  
  376. static void send_msg_to_channel(fromname, channel, text)
  377. char  *fromname;
  378. int  channel;
  379. char  *text;
  380. {
  381.  
  382.   char  buffer[2048];
  383.   register struct connection *p;
  384.  
  385.   for (p = connections; p; p = p->next)
  386.     if (p->type == CT_USER && p->channel == channel)
  387.       if (p->via) {
  388.     if (!p->via->locked) {
  389.       sprintf(buffer, "/\377\200CMSG %s %d %s\n", fromname, channel, text);
  390.       appendstring(&p->via->obuf, buffer);
  391.       p->via->locked = 1;
  392.     }
  393.       } else {
  394.     if (!p->locked) {
  395.       sprintf(buffer, "<%s>:", fromname);
  396.       appendstring(&p->obuf, formatline(buffer, text));
  397.       p->locked = 1;
  398.     }
  399.       }
  400. }
  401.  
  402. /*---------------------------------------------------------------------------*/
  403.  
  404. static void send_invite_msg(fromname, toname, channel)
  405. char  *fromname, *toname;
  406. int  channel;
  407. {
  408.  
  409.   static char  invitetext[] = "\n\007\007*** Message from %s at %s ...\nPlease join convers channel %d.\n\007\007\n";
  410.  
  411.   static char  responsetext[] = "*** Invitation sent to %s @ %s.";
  412.  
  413.   char  buffer[2048];
  414.   int  fd;
  415.   struct connection *p;
  416.   struct stat stbuf;
  417.   struct utmp *up;
  418.  
  419.   for (p = connections; p; p = p->next)
  420.     if (p->type == CT_USER && !strcmp(p->name, toname)) {
  421.       if (p->channel == channel) {
  422.     clear_locks();
  423.     sprintf(buffer, "*** User %s is already on this channel.", toname);
  424.     send_msg_to_user("conversd", fromname, buffer);
  425.     return;
  426.       }
  427.       if (!p->via && !p->locked) {
  428.     sprintf(buffer, invitetext, fromname, timestring(currtime), channel);
  429.     appendstring(&p->obuf, buffer);
  430.     clear_locks();
  431.     sprintf(buffer, responsetext, toname, myhostname);
  432.     send_msg_to_user("conversd", fromname, buffer);
  433.     return;
  434.       }
  435.       if (p->via && !p->via->locked) {
  436.     sprintf(buffer, "/\377\200INVI %s %s %d\n", fromname, toname, channel);
  437.     appendstring(&p->via->obuf, buffer);
  438.     return;
  439.       }
  440.     }
  441.  
  442.   while (up = getutent())
  443.     if (up->ut_type == USER_PROCESS && !strcmp(up->ut_user, toname)) {
  444.       sprintf(buffer, "/dev/%s", up->ut_line);
  445.       if (stat(buffer, &stbuf)) continue;
  446.       if ((stbuf.st_mode & 2) != 2) continue;
  447.       if ((fd = open(buffer, O_WRONLY, 0644)) < 0) continue;
  448.       sprintf(buffer, invitetext, fromname, timestring(currtime), channel);
  449.       write(fd, buffer, (unsigned) strlen(buffer));
  450.       close(fd);
  451.       endutent();
  452.       clear_locks();
  453.       sprintf(buffer, responsetext, toname, myhostname);
  454.       send_msg_to_user("conversd", fromname, buffer);
  455.       return;
  456.     }
  457.   endutent();
  458.  
  459.   for (p = connections; p; p = p->next)
  460.     if (p->type == CT_HOST && !p->locked) {
  461.       sprintf(buffer, "/\377\200INVI %s %s %d\n", fromname, toname, channel);
  462.       appendstring(&p->obuf, buffer);
  463.     }
  464.  
  465. }
  466.  
  467. /*---------------------------------------------------------------------------*/
  468.  
  469. static void update_permlinks(name, cp)
  470. char  *name;
  471. struct connection *cp;
  472. {
  473.   register struct permlink *p;
  474.  
  475.   for (p = permlinks; p; p = p->next)
  476.     if (!strcmp(p->name, name)) {
  477.       p->connection = cp;
  478.       p->statetime = currtime;
  479.       p->tries = 0;
  480.       p->waittime = 60;
  481.       p->retrytime = currtime + p->waittime;
  482.     }
  483. }
  484.  
  485. /*---------------------------------------------------------------------------*/
  486.  
  487. static void connect_permlinks()
  488. {
  489.  
  490. #define MAX_WAITTIME   (60*60*3)
  491.  
  492.   char  buffer[2048];
  493.   int  addrlen;
  494.   int  fd;
  495.   register struct connection *cp;
  496.   register struct permlink *p;
  497.   struct sockaddr *addr;
  498.  
  499.   for (p = permlinks; p; p = p->next) {
  500.     if (p->connection || p->retrytime > currtime) continue;
  501.     p->tries++;
  502.     p->waittime <<= 1;
  503.     if (p->waittime > MAX_WAITTIME) p->waittime = MAX_WAITTIME;
  504.     p->retrytime = currtime + p->waittime;
  505.     if (!(addr = build_sockaddr(p->socket, &addrlen))) continue;
  506.     if ((fd = socket(addr->sa_family, SOCK_STREAM, 0)) < 0) continue;
  507.     if (connect(fd, addr, addrlen) || !(cp = alloc_connection(fd))) {
  508.       close(fd);
  509.       continue;
  510.     }
  511.     p->connection = cp;
  512.     if (*p->command) appendstring(&cp->obuf, p->command);
  513.     appendstring(&cp->obuf, "convers\n");
  514.     sprintf(buffer, "/\377\200HOST %s\n", myhostname);
  515.     appendstring(&cp->obuf, buffer);
  516.   }
  517. }
  518.  
  519. /*---------------------------------------------------------------------------*/
  520.  
  521. static void bye_command(cp)
  522. struct connection *cp;
  523. {
  524.   register struct connection *p;
  525.  
  526.   switch (cp->type) {
  527.   case CT_UNKNOWN:
  528.     cp->type = CT_CLOSED;
  529.     break;
  530.   case CT_USER:
  531.     cp->type = CT_CLOSED;
  532.     clear_locks();
  533.     send_user_change_msg(cp->name, cp->host, cp->channel, -1);
  534.     break;
  535.   case CT_HOST:
  536.     cp->type = CT_CLOSED;
  537.     update_permlinks(cp->name, NULLCONNECTION);
  538.     for (p = connections; p; p = p->next)
  539.       if (p->via == cp) {
  540.     p->type = CT_CLOSED;
  541.     clear_locks();
  542.     send_user_change_msg(p->name, p->host, p->channel, -1);
  543.       }
  544.     break;
  545.   case CT_CLOSED:
  546.     break;
  547.   }
  548. }
  549.  
  550. /*---------------------------------------------------------------------------*/
  551.  
  552. static void channel_command(cp)
  553. struct connection *cp;
  554. {
  555.  
  556.   char  *s;
  557.   char  buffer[2048];
  558.   int  newchannel;
  559.  
  560.   s = getarg(0, 0);
  561.   if (!*s) {
  562.     sprintf(buffer, "*** You are on channel %d.\n", cp->channel);
  563.     appendstring(&cp->obuf, buffer);
  564.     return;
  565.   }
  566.   newchannel = atoi(s);
  567.   if (newchannel < 0 || newchannel > MAXCHANNEL) {
  568.     sprintf(buffer, "*** Channel numbers must be in the range 0..%d.\n", MAXCHANNEL);
  569.     appendstring(&cp->obuf, buffer);
  570.     return;
  571.   }
  572.   if (newchannel == cp->channel) {
  573.     sprintf(buffer, "*** Already on channel %d.\n", cp->channel);
  574.     appendstring(&cp->obuf, buffer);
  575.     return;
  576.   }
  577.   send_user_change_msg(cp->name, cp->host, cp->channel, newchannel);
  578.   cp->channel = newchannel;
  579.   sprintf(buffer, "*** Now on channel %d.\n", cp->channel);
  580.   appendstring(&cp->obuf, buffer);
  581. }
  582.  
  583. /*---------------------------------------------------------------------------*/
  584.  
  585. static void help_command(cp)
  586. struct connection *cp;
  587. {
  588.   appendstring(&cp->obuf, "Commands may be abbreviated. Commands are:\n");
  589.  
  590.   appendstring(&cp->obuf, "/?                   Print help information\n");
  591.   appendstring(&cp->obuf, "/BYE                 Terminate the convers session\n");
  592.   appendstring(&cp->obuf, "/CHANNEL n           Switch to channel n\n");
  593.   appendstring(&cp->obuf, "/EXIT                Terminate the convers session\n");
  594.   appendstring(&cp->obuf, "/HELP                Print help information\n");
  595.   appendstring(&cp->obuf, "/INVITE user         Invite user to join your channel\n");
  596.   appendstring(&cp->obuf, "/LINKS [LONG]        List all connections to other hosts\n");
  597.   appendstring(&cp->obuf, "/MSG user text...    Send a private message to user\n");
  598.   appendstring(&cp->obuf, "/QUIT                Terminate the convers session\n");
  599.   appendstring(&cp->obuf, "/WHO [QUICK] [LONG]  List all users and their channel numbers\n");
  600.   appendstring(&cp->obuf, "/WRITE user text...  Send a private message to user\n");
  601.  
  602.   appendstring(&cp->obuf, "***\n");
  603. }
  604.  
  605. /*---------------------------------------------------------------------------*/
  606.  
  607. static void invite_command(cp)
  608. struct connection *cp;
  609. {
  610.   char  *toname;
  611.  
  612.   toname = getarg(0, 0);
  613.   if (*toname) send_invite_msg(cp->name, toname, cp->channel);
  614. }
  615.  
  616. /*---------------------------------------------------------------------------*/
  617.  
  618. static void links_command(cp)
  619. struct connection *cp;
  620. {
  621.  
  622.   char  buffer[2048];
  623.   char  tmp[80];
  624.   int  full;
  625.   struct connection *pc;
  626.   struct permlink *pp;
  627.  
  628.   full = *(getarg(0, 0));
  629.   appendstring(&cp->obuf, full ?
  630.     "Host     State         Since NextTry Tries Queue Receivd Xmitted\n" :
  631.     "Host     State         Since\n");
  632.   for (pc = connections; pc; pc = pc->next)
  633.     if (pc->type == CT_HOST) {
  634.       sprintf(buffer,
  635.           full ?
  636.         "%-8.8s %-12s %s                   %5d %7d %7d\n" :
  637.         "%-8.8s %-12s %s\n",
  638.           pc->name,
  639.           "Connected",
  640.           timestring(pc->time),
  641.           queuelength(pc->obuf),
  642.           pc->received,
  643.           pc->xmitted);
  644.       appendstring(&cp->obuf, buffer);
  645.     }
  646.   for (pp = permlinks; pp; pp = pp->next)
  647.     if (!pp->connection || pp->connection->type != CT_HOST) {
  648.       strcpy(tmp, timestring(pp->retrytime)),
  649.       sprintf(buffer,
  650.           full ?
  651.         "%-8.8s %-12s %s  %s %5d\n" :
  652.         "%-8.8s %-12s %s\n",
  653.           pp->name,
  654.           pp->connection ? "Connecting" : "Disconnected",
  655.           timestring(pp->statetime),
  656.           tmp,
  657.           pp->tries);
  658.       appendstring(&cp->obuf, buffer);
  659.     }
  660.   appendstring(&cp->obuf, "***\n");
  661. }
  662.  
  663. /*---------------------------------------------------------------------------*/
  664.  
  665. static void msg_command(cp)
  666. struct connection *cp;
  667. {
  668.  
  669.   char  *toname, *text;
  670.   char  buffer[2048];
  671.   register struct connection *p;
  672.  
  673.   toname = getarg(0, 0);
  674.   text = getarg(0, 1);
  675.   if (!*text) return;
  676.   for (p = connections; p; p = p->next)
  677.     if (p->type == CT_USER && !strcmp(p->name, toname)) break;
  678.   if (!p) {
  679.     sprintf(buffer, "*** No such user: %s.\n", toname);
  680.     appendstring(&cp->obuf, buffer);
  681.   } else
  682.     send_msg_to_user(cp->name, toname, text);
  683. }
  684.  
  685. /*---------------------------------------------------------------------------*/
  686.  
  687. static void name_command(cp)
  688. struct connection *cp;
  689. {
  690.  
  691.   char  buffer[2048];
  692.   int  newchannel;
  693.  
  694.   strcpy(cp->name, getarg(0, 0));
  695.   if (!*cp->name) return;
  696.   cp->type = CT_USER;
  697.   strcpy(cp->host, myhostname);
  698.   sprintf(buffer, "conversd @ %s $Revision: 2.17 $  Type /HELP for help.\n", myhostname);
  699.   appendstring(&cp->obuf, buffer);
  700.   newchannel = atoi(getarg(0, 0));
  701.   if (newchannel < 0 || newchannel > MAXCHANNEL) {
  702.     sprintf(buffer, "*** Channel numbers must be in the range 0..%d.\n", MAXCHANNEL);
  703.     appendstring(&cp->obuf, buffer);
  704.   } else
  705.     cp->channel = newchannel;
  706.   send_user_change_msg(cp->name, cp->host, -1, cp->channel);
  707. }
  708.  
  709. /*---------------------------------------------------------------------------*/
  710.  
  711. static void who_command(cp)
  712. struct connection *cp;
  713. {
  714.  
  715.   char  buffer[2048];
  716.   int  channel;
  717.   int  full = 0;
  718.   int  quick = 0;
  719.   struct connection *p;
  720.  
  721.   switch (*(getarg(0, 0))) {
  722.   case 'l':
  723.     full = 1;
  724.     break;
  725.   case 'q':
  726.     quick = 1;
  727.     break;
  728.   }
  729.  
  730.   if (quick) {
  731.     appendstring(&cp->obuf, "Channel Users\n");
  732.     clear_locks();
  733.     do {
  734.       channel = -1;
  735.       for (p = connections; p; p = p->next)
  736.     if (p->type == CT_USER && !p->locked && (channel < 0 || channel == p->channel)) {
  737.       if (channel < 0) {
  738.         channel = p->channel;
  739.         sprintf(buffer, "%7d", channel);
  740.       }
  741.       strcat(buffer, " ");
  742.       strcat(buffer, p->name);
  743.       p->locked = 1;
  744.     }
  745.       if (channel >= 0) {
  746.     strcat(buffer, "\n");
  747.     appendstring(&cp->obuf, buffer);
  748.       }
  749.     } while (channel >= 0);
  750.     appendstring(&cp->obuf, "***\n");
  751.     return;
  752.   }
  753.  
  754.   appendstring(&cp->obuf, full ?
  755.       "User     Host     Via      Channel   Time Queue Receivd Xmitted\n" :
  756.       "User     Host     Via      Channel   Time\n");
  757.   for (p = connections; p; p = p->next)
  758.     if (p->type == CT_USER) {
  759.       sprintf(buffer,
  760.           full ?
  761.         "%-8.8s %-8.8s %-8.8s %7d %s %5d %7d %7d\n" :
  762.         "%-8.8s %-8.8s %-8.8s %7d %s\n",
  763.           p->name,
  764.           p->host,
  765.           p->via ? p->via->name : "",
  766.           p->channel,
  767.           timestring(p->time),
  768.           queuelength(p->obuf),
  769.           p->received,
  770.           p->xmitted);
  771.       appendstring(&cp->obuf, buffer);
  772.     }
  773.   appendstring(&cp->obuf, "***\n");
  774. }
  775.  
  776. /*---------------------------------------------------------------------------*/
  777.  
  778. static void h_cmsg_command(cp)
  779. struct connection *cp;
  780. {
  781.  
  782.   char  *name;
  783.   char  *text;
  784.   int  channel;
  785.  
  786.   name = getarg(0, 0);
  787.   channel = atoi(getarg(0, 0));
  788.   text = getarg(0, 1);
  789.   if (*text) send_msg_to_channel(name, channel, text);
  790. }
  791.  
  792. /*---------------------------------------------------------------------------*/
  793.  
  794. static void h_host_command(cp)
  795. struct connection *cp;
  796. {
  797.  
  798.   char  *name;
  799.   char  buffer[2048];
  800.   register struct connection *p;
  801.   register struct permlink *pp;
  802.  
  803.   name = getarg(0, 0);
  804.   if (!*name) return;
  805.   for (p = connections; p; p = p->next)
  806.     if (!strcmp(p->name, name)) bye_command(p);
  807.   for (pp = permlinks; pp; pp = pp->next)
  808.     if (!strcmp(pp->name, name) && pp->connection && pp->connection != cp)
  809.       bye_command((strcmp(myhostname, name) < 0) ? pp->connection : cp);
  810.   if (cp->type != CT_UNKNOWN) return;
  811.   cp->type = CT_HOST;
  812.   strcpy(cp->name, name);
  813.   update_permlinks(name, cp);
  814.   sprintf(buffer, "/\377\200HOST %s\n", myhostname);
  815.   appendstring(&cp->obuf, buffer);
  816.   for (p = connections; p; p = p->next)
  817.     if (p->type == CT_USER) {
  818.       sprintf(buffer, "/\377\200USER %s %s %d %d %d\n", p->name, p->host, 0, -1, p->channel);
  819.       appendstring(&cp->obuf, buffer);
  820.     }
  821. }
  822.  
  823. /*---------------------------------------------------------------------------*/
  824.  
  825. static void h_invi_command(cp)
  826. struct connection *cp;
  827. {
  828.  
  829.   char  *fromname, *toname;
  830.   int  channel;
  831.  
  832.   fromname = getarg(0, 0);
  833.   toname = getarg(0, 0);
  834.   channel = atoi(getarg(0, 0));
  835.   send_invite_msg(fromname, toname, channel);
  836. }
  837.  
  838. /*---------------------------------------------------------------------------*/
  839.  
  840. static void h_umsg_command(cp)
  841. struct connection *cp;
  842. {
  843.   char  *fromname, *toname, *text;
  844.  
  845.   fromname = getarg(0, 0);
  846.   toname = getarg(0, 0);
  847.   text = getarg(0, 1);
  848.   if (*text) send_msg_to_user(fromname, toname, text);
  849. }
  850.  
  851. /*---------------------------------------------------------------------------*/
  852.  
  853. static void h_user_command(cp)
  854. struct connection *cp;
  855. {
  856.  
  857.   char  *host;
  858.   char  *name;
  859.   int  newchannel;
  860.   int  oldchannel;
  861.   register struct connection *p;
  862.  
  863.   name = getarg(0, 0);
  864.   host = getarg(0, 0);
  865.   getarg(0, 0);            /*** ignore this argument, protocol has changed ***/
  866.   oldchannel = atoi(getarg(0, 0));
  867.   newchannel = atoi(getarg(0, 0));
  868.  
  869.   for (p = connections; p; p = p->next)
  870.     if (p->type == CT_USER       &&
  871.     p->channel == oldchannel &&
  872.     p->via == cp             &&
  873.     !strcmp(p->name, name)   &&
  874.     !strcmp(p->host, host))  break;
  875.   if (!p) {
  876.     p = (struct connection *) cxallocw(1, sizeof(struct connection ));
  877.     p->type = CT_USER;
  878.     strcpy(p->name, name);
  879.     strcpy(p->host, host);
  880.     p->via = cp;
  881.     p->channel = oldchannel;
  882.     p->time = currtime;
  883.     p->next = connections;
  884.     connections = p;
  885.   }
  886.   if ((p->channel = newchannel) < 0) p->type = CT_CLOSED;
  887.   send_user_change_msg(name, host, oldchannel, newchannel);
  888. }
  889.  
  890. /*---------------------------------------------------------------------------*/
  891.  
  892. static void process_input(cp)
  893. struct connection *cp;
  894. {
  895.  
  896.   static struct cmdtable {
  897.     char  *name;
  898.     void (*fnc)();
  899.     int  states;
  900.   } cmdtable[] = {
  901.  
  902.     "?",          help_command,       CM_USER,
  903.     "bye",        bye_command,        CM_USER,
  904.     "channel",    channel_command,    CM_USER,
  905.     "exit",       bye_command,        CM_USER,
  906.     "help",       help_command,       CM_USER,
  907.     "invite",     invite_command,     CM_USER,
  908.     "links",      links_command,      CM_USER,
  909.     "msg",        msg_command,        CM_USER,
  910.     "name",       name_command,       CM_UNKNOWN,
  911.     "quit",       bye_command,        CM_USER,
  912.     "who",        who_command,        CM_USER,
  913.     "write",      msg_command,        CM_USER,
  914.  
  915.     "\377\200cmsg", h_cmsg_command,   CM_HOST,
  916.     "\377\200host", h_host_command,   CM_UNKNOWN,
  917.     "\377\200invi", h_invi_command,   CM_HOST,
  918.     "\377\200umsg", h_umsg_command,   CM_HOST,
  919.     "\377\200user", h_user_command,   CM_HOST,
  920.  
  921.     0, 0, 0
  922.   };
  923.  
  924.   char  *arg;
  925.   char  buffer[2048];
  926.   int  arglen;
  927.   struct cmdtable *cmdp;
  928.  
  929.   clear_locks();
  930.   cp->locked = 1;
  931.  
  932.   if (*cp->ibuf == '/') {
  933.     arglen = strlen(arg = getarg(cp->ibuf + 1, 0));
  934.     for (cmdp = cmdtable; cmdp->name; cmdp++)
  935.       if (!strncmp(cmdp->name, arg, arglen)) {
  936.     if (cmdp->states & (1 << cp->type)) (*cmdp->fnc)(cp);
  937.     return;
  938.       }
  939.     if (cp->type == CT_USER) {
  940.       sprintf(buffer, "*** Unknown command '/%s'. Type /HELP for help.\n", arg);
  941.       appendstring(&cp->obuf, buffer);
  942.     }
  943.     return;
  944.   }
  945.  
  946.   if (cp->type == CT_USER)
  947.     send_msg_to_channel(cp->name, cp->channel, cp->ibuf);
  948. }
  949.  
  950. /*---------------------------------------------------------------------------*/
  951.  
  952. static void read_configuration()
  953. {
  954.  
  955.   FILE * fp;
  956.   char  *conffile = "/tcp/convers.conf";
  957.   char  *host_name, *sock_name;
  958.   char  line[1024];
  959.   struct permlink *p;
  960.  
  961.   if (!(fp = fopen(conffile, "r"))) return;
  962.   if (fgets(line, sizeof(line), fp)) {
  963.     host_name = getarg(line, 0);
  964.     if (*host_name)
  965.       myhostname = strcpy(mxallocw((unsigned) (strlen(host_name) + 1)), host_name);
  966.   }
  967.   while (fgets(line, sizeof(line), fp)) {
  968.     host_name = getarg(line, 0);
  969.     sock_name = getarg(0, 0);
  970.     if (*host_name && *sock_name) {
  971.       p = (struct permlink *) cxallocw(1, sizeof(struct permlink ));
  972.       strcpy(p->name, host_name);
  973.       strcpy(p->socket, sock_name);
  974.       strcpy(p->command, getarg(0, 1));
  975.       p->next = permlinks;
  976.       permlinks = p;
  977.       update_permlinks(host_name, NULLCONNECTION);
  978.     }
  979.   }
  980.   fclose(fp);
  981. }
  982.  
  983. /*---------------------------------------------------------------------------*/
  984.  
  985. main(argc, argv)
  986. int  argc;
  987. char  **argv;
  988. {
  989.  
  990.   static char  *socketnames[] = {
  991.     "unix:/tcp/sockets/convers",
  992. /** "*:convers",                  Currently not used **/
  993.     (char *) 0
  994.   };
  995.  
  996.   static struct timeval select_timeout = {
  997.     60, 0
  998.   };
  999.  
  1000.   char  buffer[2048];
  1001.   int  addrlen;
  1002.   int  arg;
  1003.   int  flisten[_NFILE], flistenmask[_NFILE];
  1004.   int  i;
  1005.   int  nfd, rmask, wmask;
  1006.   int  size;
  1007.   struct connection *cp;
  1008.   struct mbuf *bp;
  1009.   struct sigvec vec;
  1010.   struct sockaddr *addr;
  1011.  
  1012.   umask(022);
  1013.   for (i = 0; i < _NFILE; i++) close(i);
  1014.   chdir("/");
  1015.   setpgrp();
  1016.   vec.sv_mask = vec.sv_flags = 0;
  1017.   vec.sv_handler = sigpipe_handler;
  1018.   sigvector(SIGPIPE, &vec, (struct sigvec *) 0);
  1019.   if (!getenv("TZ")) putenv("TZ=MEZ-1MESZ");
  1020.   uname(&utsname);
  1021.   myhostname = utsname.nodename;
  1022.   time(&currtime);
  1023.  
  1024.   if (argc < 2) {
  1025.     read_configuration();
  1026.   } else {
  1027.     socketnames[0] = argv[1];
  1028.     socketnames[1] = (char *) 0;
  1029.   }
  1030.  
  1031.   for (i = 0; socketnames[i]; i++) {
  1032.     flistenmask[i] = 0;
  1033.     if (addr = build_sockaddr(socketnames[i], &addrlen)) {
  1034.       if ((flisten[i] = socket(addr->sa_family, SOCK_STREAM, 0)) >= 0) {
  1035.     switch (addr->sa_family) {
  1036.     case AF_UNIX:
  1037.       unlink(addr->sa_data);
  1038.       break;
  1039.     case AF_INET:
  1040.       arg = 1;
  1041.       setsockopt(flisten[i], SOL_SOCKET, SO_REUSEADDR, (char *) &arg, sizeof(arg));
  1042.       break;
  1043.     }
  1044.     if (!bind(flisten[i], addr, addrlen) && !listen(flisten[i], SOMAXCONN)) {
  1045.       flistenmask[i] = (1 << flisten[i]);
  1046.     } else {
  1047.       close(flisten[i]);
  1048.     }
  1049.       }
  1050.     }
  1051.   }
  1052.  
  1053.   for (; ; ) {
  1054.  
  1055.     free_closed_connections();
  1056.  
  1057.     connect_permlinks();
  1058.  
  1059.     nfd = rmask = wmask = 0;
  1060.     for (i = 0; socketnames[i]; i++)
  1061.       if (flistenmask[i]) {
  1062.     if (nfd <= flisten[i]) nfd = flisten[i] + 1;
  1063.     rmask |= flistenmask[i];
  1064.       }
  1065.     for (cp = connections; cp; cp = cp->next) {
  1066.       if (nfd <= cp->fd) nfd = cp->fd + 1;
  1067.       rmask |= cp->fmask;
  1068.       if (cp->obuf) wmask |= cp->fmask;
  1069.     }
  1070.     if (select(nfd, &rmask, &wmask, (int *) 0, &select_timeout) < 1)
  1071.       rmask = wmask = 0;
  1072.  
  1073.     time(&currtime);
  1074.  
  1075.     for (i = 0; socketnames[i]; i++)
  1076.       if (rmask & flistenmask[i]) accept_connect_request(flisten[i]);
  1077.  
  1078.     for (cp = connections; cp; cp = cp->next) {
  1079.  
  1080.       if (rmask & cp->fmask)
  1081.     if ((size = read(cp->fd, buffer, sizeof(buffer))) <= 0)
  1082.       bye_command(cp);
  1083.     else {
  1084.       cp->received += size;
  1085.       for (i = 0; i < size; i++)
  1086.         switch (buffer[i]) {
  1087.         case '\b':
  1088.           if (cp->icnt) cp->icnt--;
  1089.           break;
  1090.         case '\n':
  1091.         case '\r':
  1092.           if (cp->icnt) {
  1093.         cp->ibuf[cp->icnt] = '\0';
  1094.         process_input(cp);
  1095.         cp->icnt = 0;
  1096.           }
  1097.           break;
  1098.         default:
  1099.           if (cp->icnt < sizeof(cp->ibuf) - 5)
  1100.         cp->ibuf[cp->icnt++] = buffer[i];
  1101.           break;
  1102.         }
  1103.     }
  1104.  
  1105.       if (wmask & cp->fmask) {
  1106.     size = write(cp->fd, cp->obuf->data, (unsigned) strlen(cp->obuf->data));
  1107.     if (size < 0)
  1108.       bye_command(cp);
  1109.     else {
  1110.       cp->xmitted += size;
  1111.       cp->obuf->data += size;
  1112.       while ((bp = cp->obuf) && !*cp->obuf->data) {
  1113.         cp->obuf = cp->obuf->next;
  1114.         xfree(bp);
  1115.       }
  1116.     }
  1117.       }
  1118.  
  1119.     }
  1120.   }
  1121. }
  1122.  
  1123.